/**
 * 
 */
package org.simpleDom;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;


/**
 * @author dodekane
 *
 */
public class DomManager {
    
    Document currentDocument;
    String currentFileName;
    
    public static Document loadFile(String fileName){
        Document result = null;
        try{
            DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
            DocumentBuilder constructeur = fabrique.newDocumentBuilder();
            File xml = new File(fileName);
            result = constructeur.parse(xml); 
            removeEmptyText(result.getDocumentElement());
        }catch(ParserConfigurationException pce){
            pce.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return  result;
    }
    
    
     static void removeEmptyText(Element elem){
        NodeList childs = elem.getChildNodes();
        Node node = elem.getFirstChild();
        while(node!=null){
            if(node.getNodeType()==Node.TEXT_NODE&&node.getNodeValue()!=null&&node.getNodeValue().matches("\\A[ \n\t\b]*\\Z")){
                Node nodeToRemove = node;
                node = node.getNextSibling();
                elem.removeChild(nodeToRemove);
            }else if(node.getNodeType()==Node.ELEMENT_NODE){
                removeEmptyText((Element)node);
                node = node.getNextSibling();
            }else{
                node = node.getNextSibling();
            }
            
        }
        
        
    }
    
    public static Document createEmptyDocument(String rootElementName){
        DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
        DocumentBuilder constructeur = null;
        try {
            constructeur = fabrique.newDocumentBuilder();
        } catch (ParserConfigurationException e1) {
            e1.printStackTrace();
        }
        Document currentDocument = constructeur.newDocument();
        currentDocument.appendChild(currentDocument.createElement(rootElementName)); 
        return currentDocument;
    }
    
    public static Document createEmptyDocument(){
        DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
        DocumentBuilder constructeur = null;
        try {
            constructeur = fabrique.newDocumentBuilder();
        } catch (ParserConfigurationException e1) {
            e1.printStackTrace();
        }
        Document currentDocument = constructeur.newDocument();
        return currentDocument;
    }
    

    public static void saveDocument(Element elem,String fileName){
	Document doc = createEmptyDocument();
	doc.appendChild(elem);
        try {
            Source source = new DOMSource(doc);
            File file = new File(fileName);
            Result result = new StreamResult(file);
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            //transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
            transformer.transform(source, result);
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }
    }
    
    
    public static void saveDocument(Document doc,String fileName){
        try {
            Source source = new DOMSource(doc);
            File file = new File(fileName);
            Result result = new StreamResult(file);
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            //transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
            transformer.transform(source, result);
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }
    }
    
    
    
    static Node  getNodeFromPath(Document doc,String path){
        List pathAsListOfPosition = pathToPositionList(path);
        Node currentNode = doc.getDocumentElement();
        Iterator iter = pathAsListOfPosition.iterator();
        while (iter.hasNext()) {
            Integer position = (Integer) iter.next();
            currentNode = currentNode.getChildNodes().item(position.intValue());
        }
        return currentNode;
    }
    
    static List<Integer>  pathToPositionList(String path){
        List<Integer> result = new ArrayList<Integer>();
        if(path!=null){
            String[] positions = path.split("/");
            for (int i = 0; i < positions.length; i++) {
                if(positions[i]!=null&&!positions[i].equals("")){
                    result.add(new Integer(positions[i]));
                }          
            }
        }
        return result;
    }
    
    public static void  changeElementName(Document doc,String path,String elementName){
        Node oldNode = getNodeFromPath(doc,path);
        Node newNode = doc.createElement(elementName);
        
        Node currentNode = oldNode.getFirstChild();
        while(currentNode!=null){
        	Node nodeToRemove = currentNode;
        	currentNode = currentNode.getNextSibling();
            oldNode.removeChild(nodeToRemove);
            newNode.appendChild(nodeToRemove);
        }
        
        Node parent = oldNode.getParentNode();
        parent.replaceChild(newNode, oldNode);
        
        if(oldNode.getNodeType()==Node.ELEMENT_NODE){
        	Element oldElement = (Element)oldNode;
        	
        	NamedNodeMap att = oldElement.getAttributes();
            for (int i = 0,n = att.getLength(); i <n ; i++) {
            	Attr currentAttribute = (Attr)att.item(0);
            	oldElement.removeAttributeNode(currentAttribute);
            	newNode.getAttributes().setNamedItem(currentAttribute);
    		}
        }
    }
    
    public static void  appendChildElement(Document doc,String path,String elementName){
        Node node = getNodeFromPath(doc,path);
        node.appendChild(doc.createElement(elementName));
    }
    
    public static void  appendPreviousElement(Document doc,String path,String elementName){
        Node node = getNodeFromPath(doc,path);
        Node parent = node.getParentNode();
        parent.insertBefore(doc.createElement(elementName),node);        
    }
    
    public static void  appendNextElement(Document doc,String path,String elementName){
        Node node = getNodeFromPath(doc,path);
        Node parent = node.getParentNode();
        Node next = node.getNextSibling();
        if(next!=null){
            parent.insertBefore(doc.createElement(elementName),next); 
        }else{
            parent.appendChild(doc.createElement(elementName));
        }
               
    }
    
    public static void  setAttribute(Document doc,String path,String attributeName,String attributeValue){
        Node node = getNodeFromPath(doc,path);
        if (node instanceof Element) {
            Element elem = (Element) node;
            elem.setAttribute(attributeName,attributeValue);
        }
    }
    
    
    public static void changeAttributeName(Document doc, String path, String oldAttributeName, String newAttributeName) {
        Node node = getNodeFromPath(doc,path);
        if (node instanceof Element) {
            Element elem = (Element) node;
            String attributeValue = elem.getAttribute(oldAttributeName);
            elem.removeAttribute(oldAttributeName);
            elem.setAttribute(newAttributeName,attributeValue);
        }
    }
 
    public static void removeAttribute(Document doc, String path, String attributeName) {
        Node node = getNodeFromPath(doc,path);
        if (node instanceof Element) {
            Element elem = (Element) node;
            elem.removeAttribute(attributeName);
        }
    }
    
    public static void  appendText(Document doc,String path,String text){
        Node node = getNodeFromPath(doc,path);
        node.appendChild(doc.createTextNode(text));
    }
    
    public static void changeText(Document doc, String path, String text) {
        Node node = getNodeFromPath(doc,path);
        if (node.getNodeType()==Node.TEXT_NODE) {
           node.setTextContent(text);            
        }
    }

    public static void  remove(Document doc,String path){
        Node node = getNodeFromPath(doc,path);
        Node parent = node.getParentNode();
        parent.removeChild(node);
    }
    
    /*public static void render(String filePath,String includeDeclaration,String xsltFilePath,ServletResponse response){
        render(filePath,"/",includeDeclaration, xsltFilePath, response);
    }*/
    /*
    public static void render(String filePath,String rootXmlPath,String xsltFilePath){
        try {
            Document doc = loadFile(filePath);            
            Source source = new DOMSource(DomManager.getNodeFromPath(doc,rootXmlPath));
            Result resultat = new StreamResult(response.getOutputStream());
            TransformerFactory tfabrique = TransformerFactory.newInstance();
            StreamSource stylesource = new StreamSource(new File(xsltFilePath));
            Transformer transformer = tfabrique.newTransformer(stylesource);
            //Transformer transformer = tfabrique.newTransformer();
            //transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setParameter("filePath",filePath);
            transformer.setParameter("rootXmlPath",(rootXmlPath==null?"":rootXmlPath));
            //transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
            transformer.transform(source,resultat);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    public static void render(Document doc ,String xsltFilePath,ServletResponse response,List<KeyValue> keyValues){
        try {
            Source source = new DOMSource(doc);
            Result resultat = new StreamResult(response.getOutputStream());
            
            TransformerFactory tfabrique = TransformerFactory.newInstance();
            Transformer transformer = tfabrique.newTransformer(new StreamSource(new File(xsltFilePath)));
            //Transformer transformer = tfabrique.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            //transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
            if(keyValues!=null){
                KeyValue current = null;
                for (Iterator<KeyValue> iter = keyValues.iterator(); iter.hasNext();) {
                    current =  iter.next();
                    transformer.setParameter(current.getKey(),current.getValue());
                }
            }
            transformer.transform(source,resultat);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    
    
    public static void write(Document doc,ServletResponse response,List<KeyValue> keyValues){
        try {
            Source source = new DOMSource(doc);
            Result resultat = new StreamResult(response.getOutputStream());
            TransformerFactory tfabrique = TransformerFactory.newInstance();
            //StreamSource stylesource = new StreamSource(new File(xsltFilePath));
            //Transformer transformer = tfabrique.newTransformer(stylesource);
            Transformer transformer = tfabrique.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            if(keyValues!=null){
                KeyValue current = null;
                for (Iterator<KeyValue> iter = keyValues.iterator(); iter.hasNext();) {
                    current =  iter.next();
                    transformer.setParameter(current.getKey(),current.getValue());
                }
            }
            //transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            //transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
            transformer.transform(source,resultat);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    */
    public static void main(String[] args) {
        DomManager dm = new DomManager();
        /*List pathList = dm.getElementFromPath("/0/1/2");
         
         
        for (int i = 0; i < pathList.size(); i++) {
            System.out.println(pathList.get(i));
        }
        
        
        //dm.createEmptyDocument("Root");
        dm.setAttibute("/","id","0");
        dm.appendChildElement("/","A");
        dm.appendChildElement("/0","AA");
        
        dm.appendChildElement("/","B");
        dm.appendChildElement("/1","BB");
        
        dm.remove("/1/0");
        
        dm.saveAs("test.xml","/0");*/
    }


    public static class KeyValue {
        
        String key;
        String value;
        
        public String getKey() {
            return key;
        }
        
        public KeyValue setKey(String key) {
            this.key = key;
            return this;
        }
        
        public String getValue() {
            return value;
        }
        
        public KeyValue setValue(String value) {
            this.value = value;
            return this;
        }
    }


    
    





    
    
}
